package cn.shoptnt.framework.validation.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.shoptnt.framework.validation.annotation.RichTextSafeDomain;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 自定义注解 @RichTextSafeDomain实现类
 *
 * @author LiuXT
 */
public class RichTextSafeDomainValidator implements ConstraintValidator<RichTextSafeDomain, String> {

    /**
     * richTextSafeDomain-正则表达式校验 pattern
     * 含义：以<img src="或<img src=\"开头，其次为http://或https://或空(意味着接下来必是域名)，后第一个/或第一个"(引号)之间的内容则为正确匹配的内容，在进行group(3)获取到域名部分
     * 如：<img src=\"https://a.com/a.jpg"中，group(3)将获取到 "a.com"
     * 如：<img src=""中，group(3)将获取到 ""
     */
    public static Pattern richTextSafeDomainPattern = Pattern.compile("<img src=(\\\\\"|\")(http://|https://|)(.*?)[/\"]");

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return checkRichTextParam(value);
    }

    @Override
    public void initialize(RichTextSafeDomain constraintAnnotation) {

    }

    /**
     * 根据白名单校验域名-富文本参数
     * 使用正则匹配到域名部分，对域名进行白名单校验，合法即返回true放行，否则返回false
     *
     * @param value String富文本参数
     * @return 合法域名则返回true，否则返回false
     */
    public static boolean checkRichTextParam(String value) {
        // 当白名单以及参数 都不为空时，进行校验；而都为空时直接放行
        if (ObjectUtil.isNotEmpty(SafeDomainValidator.urlWhiteList) && ObjectUtil.isNotEmpty(value)) {
            // 当参数中出现“<img src=”字符串（作为参数传递特殊符号"<"等会自动转义为"&lt";，而img标签会按照"<"字符串传递），而并非img标签时，放行
            if (!value.contains("<img src=")) {
                return true;
            }
            // 进行校验
            Matcher matcher = richTextSafeDomainPattern.matcher(value);
            List<String> groupList = new ArrayList<>();
            boolean flag = true;
            // 根据表达式，获取到参数中的域名部分，若白名单包含则表示校验成功，否则校验失败
            while (matcher.find()) {
                String groupThree = matcher.group(3);
                groupList.add(groupThree);
            }
            for (String group : groupList) {
                // 特殊情况：<img src="" title="123123.jpg>，当src无内容时放行
                if (ObjectUtil.isEmpty(group)) {
                    continue;
                }
                //如果白名单中不包含参数中的域名部分，则校验失败
                if (!SafeDomainValidator.urlWhiteList.contains(group)) {
                    return false;
                }
            }
        }
        return true;
    }
}
